import { IVec2 } from "../../util/Defined";
import { MathUtil } from "../../util/MathUtil";
import { TypeUtil } from "../../util/TypeUtil";

/**
 * 二维对象
 */
export class Vec2 implements IVec2 {
	/** 零点 */
	static readonly ZERO = TypeUtil.readonlyType(new Vec2(0, 0));
	/** 右方向 */
	static readonly RIGHT = TypeUtil.readonlyType(new Vec2(1, 0));
	/** 左方向 */
	static readonly LEFT = TypeUtil.readonlyType(new Vec2(-1, 0));
	/** 上方向 */
	static readonly UP = TypeUtil.readonlyType(new Vec2(0, 1));
	/** 下方向 */
	static readonly DOWN = TypeUtil.readonlyType(new Vec2(0, -1));
	/** (1,1) */
	static readonly ONE = TypeUtil.readonlyType(new Vec2(1, 1));
	/** (-1,-1) */
	static readonly NEG_ONE = TypeUtil.readonlyType(new Vec2(-1, -1));
	/** 临时变量 */
	static readonly T = new Vec2();
	/** 临时变量 */
	static readonly T2 = new Vec2();
	/** 临时变量 */
	static readonly T3 = new Vec2();
	/** 临时变量 */
	static readonly T4 = new Vec2();
	/** 临时变量 */
	static readonly T5 = new Vec2();
	/** 设置临时变量 */
	static TPos(x: number, y: number) { return this.T.setPos(x, y); }
	/** 设置临时变量 */
	static TPosTo(pos: Readonly<IVec2>) { return this.T.setPosTo(pos); }


	/** 内部临时变量 */
	protected static readonly _tpos = new Vec2();

	/**
	 * 复制坐标生成一个新的二维对象
	 * @param pos
	 */
	static copyPos(pos: Readonly<IVec2>) {
		return new Vec2(pos.x, pos.y);
	}

	/**
	 * 重置坐标为零点
	 * @param out
	 */
	static resetPos<T extends IVec2>(out: T) {
		out.x = 0;
		out.y = 0;
		return out;
	}

	/**
	 * 设置坐标
	 * @param out
	 * @param x
	 * @param y
	 */
	static setPos<T extends IVec2>(out: T, x: number, y: number) {
		out.x = x;
		out.y = y;
		return out;
	}

	/**
	 * 设置坐标
	 * @param out
	 * @param pos
	 */
	static setPosTo<T extends IVec2>(out: T, pos: Readonly<IVec2>) {
		out.x = pos.x;
		out.y = pos.y;
		return out;
	}

	/**
	 * 增值坐标
	 * @param out
	 * @param x
	 * @param y
	 */
	static addPos<T extends IVec2>(out: T, x: number, y: number) {
		out.x += x;
		out.y += y;
		return out;
	}

	/**
	 * 增值坐标
	 * @param out
	 * @param pos
	 */
	static addPosTo<T extends IVec2>(out: T, pos: Readonly<IVec2>) {
		out.x += pos.x;
		out.y += pos.y;
		return out;
	}

	/**
	 * 两点之间的距离
	 * @param pos1
	 * @param pos2
	 */
	static dis(pos1: Readonly<IVec2>, pos2: Readonly<IVec2>) {
		const x = pos1.x - pos2.x;
		const y = pos1.y - pos2.y;
		return Math.sqrt(x * x + y * y);
	}

	/**
	 * 将方向设置为弧度方向
	 * @param dir
	 * @param rad
	 */
	static setRad<T extends IVec2>(dir: T, rad: number) {
		dir.x = Math.cos(rad);
		dir.y = Math.sin(rad);
		return dir;
	}

	/**
	 * 获取方向的弧度
	 * @param dir
	 */
	static getRad(dir: Readonly<IVec2>) {
		return Math.atan2(dir.y, dir.x);
	}

	/**
	 * 位置1朝向位置2的弧度
	 * @param pos1 位置1
	 * @param pos2 位置2
	 */
	static radTo(pos1: Readonly<IVec2>, pos2: Readonly<IVec2>) {
		return Math.atan2(pos2.y - pos1.y, pos2.x - pos1.x);
	}

	/**
	 * 位置1朝向位置2的方向
	 * @param pos1 位置1
	 * @param pos2 位置2
	 * @param out 如未设置则返回的是临时变量 请勿保持引用
	 */
	static dirTo(pos1: IVec2, pos2: Readonly<IVec2>, out: IVec2 = this._tpos) {
		out.x = pos2.x - pos1.x;
		out.y = pos2.y - pos1.y;
		return this.normalize(out);
	}

	/**
	 * 朝目标方向移动dis距离
	 * @param pos 当前位置
	 * @param target 目标位置
	 */
	static move<T extends IVec2>(pos: T, dir: Readonly<IVec2>, dis: number) {
		return this.addPos(pos, dir.x * dis, dir.y * dis);
	}

	/**
	 * 朝目标方向移动dis距离
	 * @param pos 当前位置
	 * @param target 目标位置
	 */
	static moveTo<T extends IVec2>(pos: T, target: Readonly<IVec2>, dis: number) {
		const rad = this.radTo(pos, target);
		return this.moveRad(pos, rad, dis);
	}

	/**
	 * 朝弧度方向移动dis距离
	 * @param pos 当前位置
	 * @param rad 弧度方向
	 * @param dis 移动距离
	 */
	static moveRad<T extends IVec2>(pos: T, rad: number, dis: number) {
		pos.x += Math.cos(rad) * dis;
		pos.y += Math.sin(rad) * dis;
		return pos;
	}

	/**
	 * 计算向量的长度（模）
	 * @param pos
	 */
	static len(pos: Readonly<IVec2>) {
		return Math.sqrt(this.lenSqr(pos));
	}

	/**
	 * 计算向量长度（模）的平方。
	 * @param pos
	 */
	static lenSqr(pos: Readonly<IVec2>) {
		return pos.x * pos.x + pos.y * pos.y;
	}

	/**
	 * 归一化向量
	 * @param pos
	 */
	static normalize<T extends IVec2>(pos: T) {
		let len = this.lenSqr(pos);
		if (len > 0) {
			len = 1 / Math.sqrt(len);
			pos.x *= len;
			pos.y *= len;
		}
		return pos;
	}

	/**
	 * 坐标线性插值
	 * @param pos
	 * @param target
	 * @param t
	 */
	static lerp<T extends IVec2>(pos: T, target: Readonly<IVec2>, t: number) {
		pos.x = MathUtil.lerp(pos.x, target.x, t);
		pos.y = MathUtil.lerp(pos.y, target.y, t);
		return pos;
	}

	/**
	 * 一个坐标是否等于另一个坐标
	 * @param pos
	 * @param target
	 */
	static equalsPos(pos: Readonly<IVec2>, target: Readonly<IVec2>) {
		return pos.x === target.x && pos.y === target.y;
	}

	constructor(public x = 0, public y = 0) { }

	/**
	 * 复制当前坐标生成一个新的二维对象
	 */
	copyPos() {
		return new Vec2(this.x, this.y);
	}

	/**
	 * 重置坐标为零点
	 */
	resetPos() {
		return Vec2.resetPos(this);
	}

	/**
	 * 设置坐标
	 * @param x
	 * @param y
	 */
	setPos(x = 0, y = 0) {
		return Vec2.setPos(this, x, y);
	}

	/**
	 * 设置坐标
	 * @param pos
	 */
	setPosTo(pos: Readonly<IVec2>) {
		return Vec2.setPosTo(this, pos);
	}

	/**
	 * 增值坐标
	 * @param out
	 * @param x
	 * @param y
	 */
	addPos(x: number, y: number) {
		return Vec2.addPos(this, x, y);
	}

	/**
	 * 增值坐标
	 * @param out
	 * @param pos
	 */
	addPosTo(pos: Readonly<IVec2>) {
		return Vec2.addPosTo(this, pos);
	}

	/**
	 * 距离目标的距离
	 * @param pos
	 */
	dis(pos: Readonly<IVec2>) {
		return Vec2.dis(this, pos);
	}

	/**
	 * 设置为弧度方向
	 * @param rad
	 */
	setRad(rad: number) {
		return Vec2.setRad(this, rad);
	}

	/**
	 * 获取当前方向的弧度
	 */
	getRad() {
		return Vec2.getRad(this);
	}

	/**
	 * 朝向目标的弧度
	 * @param pos
	 */
	radTo(pos: Readonly<IVec2>) {
		return Vec2.radTo(this, pos);
	}

	/**
	 * 朝向目标的方向
	 * @param pos
	 * @param out 如未设置则返回的是临时变量 请勿保持引用
	 */
	dirTo(pos: Readonly<IVec2>, out?: IVec2) {
		return Vec2.dirTo(this, pos, out);
	}

	/**
	 * 朝坐标方向移动dis距离
	 * @param pos
	 * @param dis
	 */
	move(dir: Readonly<IVec2>, dis: number) {
		return Vec2.move(this, dir, dis);
	}

	/**
	 * 朝坐标方向移动dis距离
	 * @param pos
	 * @param dis
	 */
	moveTo(pos: Readonly<IVec2>, dis: number) {
		return Vec2.moveTo(this, pos, dis);
	}

	/**
	 * 朝弧度方向移动dis距离
	 * @param rad
	 * @param dis
	 */
	moveRad(rad: number, dis: number) {
		return Vec2.moveRad(this, rad, dis);
	}

	/**
	 * 计算向量的长度（模）
	 */
	len() {
		return Vec2.len(this);
	}

	/**
	 * 计算向量长度（模）的平方。
	 */
	lenSqr() {
		return Vec2.lenSqr(this);
	}

	/**
	 * 归一化向量
	 */
	normalize() {
		return Vec2.normalize(this);
	}

	/**
	 * 线性插值
	 * @param target
	 * @param t
	 */
	lerp(pos: Readonly<IVec2>, t: number) {
		return Vec2.lerp(this, pos, t);
	}

	/**
	 * 是否等于另一个坐标
	 * @param
	 */
	equalsPos(pos: Readonly<IVec2>) {
		return Vec2.equalsPos(this, pos);
	}

	/** 转化为字符串 */
	toString() {
		return `${this.x},${this.y}`;
	}
}
